home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-02-19 | 22.9 KB | 693 lines | [TEXT/CWIE] |
-
- #include "DBElementToken.h"
- #include "DBElementTokenIterator.h"
-
- #include "Application.h"
- #include "DBElement.h"
- #include "DBProperty.h"
- #include "Transaction.h"
- #include "ScriptableDBDocument.h"
- #include "AbstractProperty.h"
-
- #include <AERegistry.h>
- #include <ASRegistry.h>
-
- #include "Exceptions.h"
-
- TDescriptor GetDataAsDescriptor(TTransaction* t, AConst<TDBProperty> propertyRecord);
-
-
- //--------------------------------------------------------------------------------
- // GetDataAsDescriptor
- //--------------------------------------------------------------------------------
- TDescriptor GetDataAsDescriptor(TTransaction* t, AConst<TDBProperty> propertyRecord)
- {
- TDescriptor result;
-
- if(propertyRecord.Exists())
- {
- propertyRecord->GetTypedData(t, TDescriptorDataReference(result));
- }
-
- return result;
- } // GetDataAsDescriptor
-
- #define clDBElementToken 33
-
- #pragma segment ObjectResident
- ImplementSmallClassData(TDBElementToken, clDBElementToken);
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::TDBElementToken
- //--------------------------------------------------------------------------------
- TDBElementToken::TDBElementToken(AConst<TDBElement> record) : fRecord(record)
- {
- record->AddReference();
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::~TDBElementToken
- //--------------------------------------------------------------------------------
- TDBElementToken::~TDBElementToken()
- {
- fRecord->RemoveReference();
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::CloneOwnedObjects
- //--------------------------------------------------------------------------------
- void TDBElementToken::CloneOwnedObjects()
- {
- //
- // fRecord has been cloned, so we need to add one more reference to it
- //
- fRecord->AddReference();
- } // TDBElementToken::CloneOwnedObjects
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::ObjectClass
- //--------------------------------------------------------------------------------
- DescType TDBElementToken::ObjectClass(const TAETransaction& t, Boolean /*recordedClass*/)
- {
- DescType objectClass = cObject;
- long unusedLength = 0;
- long unusedType = 0;
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(TTransactionSuite::GetTransactionFromEvent(t), pClass);
-
- if(propertyRecord.Exists())
- propertyRecord->GetTypedData(TTransactionSuite::GetTransactionFromEvent(t), TUpdataDataReference(typeType, (char*)&objectClass, sizeof(DescType), sizeof(DescType)));
-
- return objectClass;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::DerivedFromOSLClass
- //--------------------------------------------------------------------------------
- Boolean TDBElementToken::DerivedFromOSLClass(const TAETransaction& t, DescType objectClass)
- {
- return ((objectClass == this->ObjectClass(t)) || (Inherited::DerivedFromOSLClass(t, objectClass)));
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::ParentObject
- //--------------------------------------------------------------------------------
- TAbstractScriptableObject* TDBElementToken::ParentObject(const TAETransaction& t)
- {
- TAbstractScriptableObject* parent = nil;
- AConst<TDBRecord> parentElement = fRecord->TreeOwner(TTransactionSuite::GetTransactionFromEvent(t));
-
- //
- // If this node has a parent, then it is not the metaroot
- //
- if(parentElement.Exists())
- {
- parent = new TDBElementToken(parentElement->DBElementCursor());
- }
- //
- // The parent of the metaroot is the scriptable db document
- // that contains this database document.
- //
- else
- {
- TDatabaseDocument* doc = fRecord->DBDocument();
- parent = TApplication::Instance()->FindDocument(doc->ObjectsKeySpace());
- }
-
- return parent;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::ElementIterator
- //--------------------------------------------------------------------------------
- TAbstractObjectIterator* TDBElementToken::ElementIterator(const TAETransaction& t)
- {
- // AConst<TDBRecord> elements = fRecord->Elements()->DBRecordCursor();
- AConst<TDBElement> elements = fRecord->Elements(TTransactionSuite::GetTransactionFromEvent(t));
-
- TAbstractObjectIterator* iter = nil;
-
- if(elements.Exists())
- {
- iter = new TDBElementTokenIterator(t, elements->DBRecordCursor());
- }
-
- return iter;
- }
-
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::AccessByProperty
- //--------------------------------------------------------------------------------
- TAbstractScriptableObject* TDBElementToken::AccessByProperty(const TAETransaction& t, DescType propertyIdentifier)
- {
- TAbstractScriptableObject* result = nil;
-
- //
- // If we can generate a description for this property,
- // then call Inherited:: to make the property token
- //
- if(this->DescriptionOfProperty(t, propertyIdentifier) != nil)
- {
- result = Inherited::AccessByProperty(t, propertyIdentifier);
- }
- else
- {
- //
- // Problem: For this database, there should be some way
- // to create a property that does not exist yet under some
- // situations (maybe some databases will allow any property
- // to be added to any element, but most databases will
- // probably restrict the properties that each element can
- // have).
- //
- // We also need to specify that some properties are read
- // only (maybe?)
- //
- #if 0
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(propertyIdentifier);
- if(propertyRecord.Exists())
- #endif
- {
- //
- // We need some way to determine what the default type
- // and best type for any given property should be.
- //
- result = new TGenericProperty;
- ((TGenericProperty*)result)->IGenericProperty(this, TPropertyDataDescription(propertyIdentifier, 0, typeWildCard, typeWildCard));
- }
- }
-
- return result;
- }
-
-
- //================================================================================
- // Class TDescriptorComparisonObject
- //================================================================================
- class TDescriptorComparisonObject : public TAbstractDBComparisonObject
- {
- private:
- const TDescriptor fSearchKey;
-
- public:
- TDescriptorComparisonObject(TDescriptor& searchKey) : fSearchKey(searchKey) {};
-
- virtual CompareEnumeration TestObject(TTransaction*, AConst<TDBRecord>);
- };
-
- //--------------------------------------------------------------------------------
- // TDescriptorComparisonObject::TestObject
- //--------------------------------------------------------------------------------
- CompareEnumeration TDescriptorComparisonObject::TestObject(TTransaction* t, AConst<TDBRecord> testObject)
- {
- //
- // This is not a very fast way to compare, but it will do for now.
- //
- TDescriptor testName = GetDataAsDescriptor(t, testObject->DBElementCursor()->GetPropertyRecord(t, pName));
-
- //
- // This AppleEvent API that removes information from the result is annoying,
- // because it forces us to compare twice (ick).
- //
- // kAEGreaterThan
- // kAELessThan
- //
- Boolean isLess = fSearchKey.Compare(kAELessThan, testName);
- Boolean isGreater = fSearchKey.Compare(kAEGreaterThan, testName);
-
- //
- // kSecondObjectComesBefore = -1,
- // kObjectKeysEqual = 0,
- // kSecondObjectComesAfter = 1
- //
- return (isGreater ? kSecondObjectComesAfter : (isLess ? kSecondObjectComesBefore : kObjectKeysEqual));
- } // TDescriptorComparisonObject::TestObject
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::AccessByUniqueID
- //--------------------------------------------------------------------------------
- TAbstractScriptableObject* TDBElementToken::AccessByUniqueID(const TAETransaction& t, DescType desiredClass, TDescriptor uniqueID)
- {
- TAbstractScriptableObject* result = nil;
- long theRecordIndex = uniqueID.GetSInt32Data();
-
- //
- // Get the specified record from the database. The record
- // _must_ be a database element (not a property); if this is
- // a token for the metaroot, then allow any record in any tree
- // to be returned. Otherwise, require that the record we found
- // be a child of this record.
- //
- AConst<TDBElement> theRecord = fRecord->DBDocument()->GetRecordCursor(theRecordIndex)->DBElementCursor();
- if(theRecord.Exists())
- {
- AConst<TDBRecord> theRecordOwner = theRecord->TreeOwner(TTransactionSuite::GetTransactionFromEvent(t));
- if(this->IsMetaRoot() || (theRecordOwner->RecordIndex() == fRecord->RecordIndex()))
- {
- result = new TDBElementToken(theRecord);
- if(result->DerivedFromOSLClass(t, desiredClass) == false)
- {
- result->DisposeDesignator();
- result = nil;
- }
- }
- }
-
- //
- // If we could not find an appropriate record with the given ID,
- // then call Inherited.
- //
- if(result == nil)
- result = Inherited::AccessByUniqueID(t, desiredClass, uniqueID);
-
- return result;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::BestType
- //--------------------------------------------------------------------------------
- DescType TDBElementToken::BestType(const TAETransaction& t, DescType propertyName)
- {
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(TTransactionSuite::GetTransactionFromEvent(t), propertyName);
- if(propertyRecord.Exists())
- {
- return propertyRecord->GetDataType(TTransactionSuite::GetTransactionFromEvent(t));
- }
- else
- return typeBest;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::DefaultType
- //--------------------------------------------------------------------------------
- DescType TDBElementToken::DefaultType(const TAETransaction& t, DescType propertyName)
- {
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(TTransactionSuite::GetTransactionFromEvent(t), propertyName);
- if(propertyRecord.Exists())
- {
- return propertyRecord->GetDataType(TTransactionSuite::GetTransactionFromEvent(t));
- }
- else
- return typeWildCard;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::CanReturnDataOfType
- //--------------------------------------------------------------------------------
- Boolean TDBElementToken::CanReturnDataOfType(const TAETransaction&, DescType /*propertyName*/, DescType /*desiredType*/)
- {
- return true;
- }
-
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::GetProperty
- //--------------------------------------------------------------------------------
- TDescriptor TDBElementToken::GetProperty(const TAETransaction& t, DescType propertyName, DescType desiredType, unsigned long additionalInfo /*= 0*/)
- {
- TDescriptor result;
-
- switch(propertyName)
- {
- case pID:
- {
- result.SetSInt32Data(fRecord->RecordIndex());
- break;
- }
-
- case pIndex:
- {
- if(this->IsMetaRoot())
- FailErr(errAENoSuchObject);
- else
- {
- long index = 0;
- AConst<TDBRecord> treeTop = fRecord->TopOfTree(TTransactionSuite::GetTransactionFromEvent(t));
- for(TAbstractRecordIterator iter(TTransactionSuite::GetTransactionFromEvent(t), treeTop); iter.More(); iter.Next())
- {
- ++index;
- if(iter.Current()->RecordIndex() == fRecord->RecordIndex())
- break;
- }
- result.SetSInt32Data(index);
- }
- break;
- }
-
- default:
- {
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(TTransactionSuite::GetTransactionFromEvent(t), propertyName);
- if(propertyRecord.Exists())
- {
- result = GetDataAsDescriptor(TTransactionSuite::GetTransactionFromEvent(t), propertyRecord);
- }
- else
- result = Inherited::GetProperty(t, propertyName, desiredType, additionalInfo);
-
- break;
- }
- }
-
- return result;
- }
-
- //----------------------------------------------------------------------------------------
- // TDBElementToken::GetProperties:
- //----------------------------------------------------------------------------------------
- TDescriptor TDBElementToken::GetProperties(const TAETransaction& t, DescType desiredType)
- {
- TDescriptor properties = Inherited::GetProperties(t, desiredType);
- TDescriptor data;
- OSErr err = noErr;
-
- AConst<TDBProperty> everyProperty = fRecord->Properties(TTransactionSuite::GetTransactionFromEvent(t));
- for(TAbstractRecordIterator iter(TTransactionSuite::GetTransactionFromEvent(t), everyProperty->DBRecordCursor()); iter.More(); iter.Next())
- {
- AConst<TDBProperty> propertyRecord = iter.Current()->DBPropertyCursor();
- DescType propertyName = propertyRecord->PropertyID(TTransactionSuite::GetTransactionFromEvent(t));
-
- //
- // Skip properties already included by the call to Inherited
- //
- // There are better ways to do this; we could check to see if
- // propertyName exists in the record 'everyProperty', or we
- // could do a lookup in the property description table. However,
- // we already know what is in the property description table,
- // so we just copy it here. That's somewhat undesirable, but
- // faster.
- //
- if( (propertyName != pName) &&
- (propertyName != pClass) &&
- (propertyName != pDefaultType) &&
- (propertyName != pBestType) &&
- (propertyName != pID) &&
- (propertyName != pIndex) )
- {
- Try
- {
- //
- // Look up the data type to get; usually it will be the default type
- // or the best type for an individual property, but sometimes another
- // data type might be specified; in that case, only properties that
- // can return the specified type will be included in the result.
- //
- DescType typeToGet = desiredType;
-
- //
- // If the type to get is 'typeNull', then a description of the
- // property without any of its data is returned.
- //
- if(typeToGet != typeNull)
- {
- data = GetDataAsDescriptor(TTransactionSuite::GetTransactionFromEvent(t), propertyRecord);
- if((typeToGet != typeWildCard) && (typeToGet != typeBest))
- this->CoerceResultToRequestedType(data, typeToGet);
- }
- properties.PutDescriptorParameter(propertyName, data);
- }
- Catch(err)
- {
- }
-
- data.Dispose();
- }
- }
-
- return properties;
- } // TAbstractScriptableObject::GetProperties
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::CompareProperty
- //--------------------------------------------------------------------------------
- Boolean TDBElementToken::CompareProperty(const TAETransaction& t, DescType propertyIdentifier, DescType comparisonOperator, TDescriptor compareWith)
- {
- Boolean compareResult = false;
- Boolean didCompare = false;
-
- AConst<TDBProperty> propertyRecord = fRecord->GetPropertyRecord(TTransactionSuite::GetTransactionFromEvent(t), propertyIdentifier);
- if(propertyRecord.Exists())
- {
- short oldState = compareWith.Lock();
-
- switch(comparisonOperator)
- {
- case kAEEquals:
- case kASNotEqual:
- case kAEGreaterThan:
- case kAEGreaterThanEquals:
- case kAELessThan:
- case kASLessThanOrEqual:
- {
- compareResult = InterpretCompareResult(comparisonOperator, propertyRecord->Compare(TTransactionSuite::GetTransactionFromEvent(t), compareWith), 0 );
- didCompare = true;
- break;
- }
-
- case kAEContains:
- {
- compareResult = propertyRecord->Contains(TTransactionSuite::GetTransactionFromEvent(t), compareWith);
- didCompare = true;
- break;
- }
-
- //
- // We don't export enough data to do begins with or
- // ends with, so we'll just call Inherited and allow
- // the comparison to be done the slow way.
- //
- case kAEBeginsWith:
- case kAEEndsWith:
- default:
- {
- didCompare = false;
- break;
- }
- }
-
- compareWith.Unlock(oldState);
- }
- else
- didCompare = false;
-
- //
- // If we couldn't do the compare, then call Inherited
- //
- if(didCompare == false)
- compareResult = Inherited::CompareProperty(t, propertyIdentifier, comparisonOperator, compareWith);
-
- return compareResult;
- } // TDBElementToken::CompareProperty
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::SetProperty
- //--------------------------------------------------------------------------------
- void TDBElementToken::SetProperty(const TAETransaction& t, DescType propertyName, TDescriptor& data, unsigned long /*additionalInfo = 0*/)
- {
- switch(propertyName)
- {
- case pIndex:
- case pID:
- {
- FailErr(errAENotModifiable);
- break;
- }
-
- default:
- {
- TTransaction* transaction = TTransactionSuite::GetTransactionFromEvent(t);
- AnUpdate<TDBElement> updateElement = transaction->GetDBElementUpdatePointer(fRecord);
-
- #if 0 // ◊ old way
- HLock(data.DataHandle());
- char* dataPtr = *data.DataHandle();
- long dataLength = GetHandleSize(data.DataHandle());
- long dataType = data.DescriptorType();
-
- updateElement->AddTypedProperty(transaction, propertyName, TConstDataReference(dataType, dataPtr, dataLength));
- HUnlock(data.DataHandle());
- #endif
- short oldState = data.Lock();
- updateElement->AddTypedProperty(transaction, propertyName, data);
- data.Unlock(oldState);
-
- //
- // Make sure that the tree is still happy
- //
- fRecord->Verify(transaction, true);
- break;
- }
- }
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::BuildObjectSpecifier
- //--------------------------------------------------------------------------------
- TDescriptor TDBElementToken::BuildObjectSpecifier(const TAETransaction& t)
- {
- //
- // If this record is the metaroot, don't build
- // an object specifier for it; just make one
- // for the parent object
- //
- if(this->IsMetaRoot())
- return this->BuildSpecifierForParent(t);
- else
- return Inherited::BuildObjectSpecifier(t);
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::MakeKeyDataForSelf
- //--------------------------------------------------------------------------------
- void TDBElementToken::MakeKeyDataForSelf(const TAETransaction& t, DescType& keyForm, TDescriptor& keyData)
- {
- //
- // If we have a name property and this record is in a tree,
- // then describe this element as "element xxx" of <parent specifier>
- //
- AConst<TDBProperty> nameProperty = fRecord->GetPropertyRecord(TTransactionSuite::GetTransactionFromEvent(t), pName);
- if(nameProperty.Exists() && fRecord->RecordIsInATree(TTransactionSuite::GetTransactionFromEvent(t)))
- {
- Inherited::MakeKeyDataForSelf(t, keyForm, keyData);
- }
- //
- // If there is no name property, OR if we have no parent, then describe
- // this element by unique ID.
- //
- else
- {
- keyForm = formUniqueID;
- keyData.SetSInt32Data(fRecord->RecordIndex());
- }
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::BuildSpecifierForParent
- //--------------------------------------------------------------------------------
- TDescriptor TDBElementToken::BuildSpecifierForParent(const TAETransaction& t)
- {
- return Inherited::BuildSpecifierForParent(t);
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::AECommand
- //--------------------------------------------------------------------------------
- TDescriptor TDBElementToken::AECommand(const TAETransaction& t, long aeCommandID, TAbstractScriptableObject* auxObjects, long auxInfo)
- {
- TTransaction* transaction = TTransactionSuite::GetTransactionFromEvent(t);
- TDescriptor result;
-
- switch(aeCommandID)
- {
- case kAEMove:
- {
- TAbstractObjectIterator* iter = auxObjects->DirectObjectIterator(t);
- AnUpdate<TDBElement> destinationElement = transaction->GetDBElementUpdatePointer(fRecord);
-
- //
- // There may be more than one item to move
- //
- for(iter->Reset(t); iter->More(t); iter->Next(t))
- {
- TAbstractScriptableObject* current = iter->Current(t);
-
- //
- // We can only move DBElements
- //
- if(current->DerivedFrom(clDBElementToken))
- {
- AnUpdate<TDBElement> oneObjectToMove = transaction->GetDBElementUpdatePointer(((TDBElementToken*)current)->Record());
-
- oneObjectToMove->RemoveFromTree(transaction);
- destinationElement->AddElement(transaction, oneObjectToMove);
-
- TDescriptor intermediate = current->BuildObjectSpecifier(t);
- result.AppendListAndDispose(intermediate);
- }
-
- current->DisposeDesignator();
- }
-
- break;
- }
-
- case kAEDelete:
- {
- result = this->BuildObjectSpecifier(t);
-
- AnUpdate<TDBElement> updateElement = transaction->GetDBElementUpdatePointer(fRecord);
- updateElement->FreeThisRecord(transaction);
-
- break;
- }
-
- default:
- {
- result = Inherited::AECommand(t, aeCommandID, auxObjects, auxInfo);
- break;
- }
- }
-
- return result;
- }
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::CreateNewElement
- //--------------------------------------------------------------------------------
- TAbstractScriptableObject* TDBElementToken::CreateNewElement(const TAETransaction& t, DescType newObjectClass, TDescriptor /*initialData*/, TDescriptor /*initialProperties*/, Boolean& /*usedInitialData*/, Boolean& /*usedInitialProperties*/)
- {
- TTransaction* transaction = TTransactionSuite::GetTransactionFromEvent(t);
- AnUpdate<TDBElement> updateElement = transaction->GetDBElementUpdatePointer(fRecord);
-
- AnUpdate<TDBElement> newElement = fRecord->DBDocument()->NewDBElement(transaction);
- newElement->AddTypedProperty(transaction, pClass, TConstDataReference(typeType, (Ptr)&newObjectClass, sizeof(DescType)));
- updateElement->AddElement(transaction, newElement);
-
- //
- // Make sure that the tree is still happy
- //
- fRecord->Verify(transaction, true);
-
- return new TDBElementToken(newElement);
- }
-
- //----------------------------------------------------------------------------------------
- // TDBElementToken::ObjectsAreTheSame:
- //----------------------------------------------------------------------------------------
- Boolean TDBElementToken::ObjectsAreTheSame(const TAETransaction&, TAbstractScriptableObject* objectToTest)
- {
- Boolean areTheSame = false;
-
- if(objectToTest->DerivedFrom(clDBElementToken))
- {
- areTheSame = ((this->RecordIndex() == ((TDBElementToken*)objectToTest)->RecordIndex()) &&
- (this->DocumentIdentifier() == ((TDBElementToken*)objectToTest)->DocumentIdentifier()));
- }
-
- return areTheSame;
- } // TDBElementToken::ObjectsAreTheSame
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::IsMetaRoot
- //--------------------------------------------------------------------------------
- Boolean TDBElementToken::IsMetaRoot()
- {
- return fRecord->RecordIndex() == fRecord->DBDocument()->MetaRootIndex();
- } // TDBElementToken::IsMetaRoot
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::RecordIndex
- //--------------------------------------------------------------------------------
- long TDBElementToken::RecordIndex()
- {
- return fRecord->RecordIndex();
- } // TDBElementToken::RecordIndex
-
- //--------------------------------------------------------------------------------
- // TDBElementToken::DocumentIdentifier
- //--------------------------------------------------------------------------------
- Int64 TDBElementToken::DocumentIdentifier()
- {
- return fRecord->DBDocument()->ObjectsKeySpace();
- } // TDBElementToken::DocumentIdentifier
-
-